package cn.git.agent;

import net.bytebuddy.implementation.bind.annotation.*;

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.concurrent.Callable;

/**
 * @description: mysql增强拦截器
 * @program: bank-credit-sy
 * @author: lixuchun
 * @create: 2024-12-23
 */
public class MySqlInterceptor {

    /**
     * 被标注 RuntimeType 注解的方法就是拦截方法，此时返回的值与返回参数可以与被拦截的方法不一致
     * byteBuddy会在运行期间给被拦截的方法参数进行赋值
     * @return
     */
    @RuntimeType
    public Object intercept(
            @This Object targetObject,
            @Origin Method targetMethod,
            @AllArguments Object[] targetMethodArgs,
            @SuperCall Callable<?> superCall) {
        Long start = System.currentTimeMillis();

        try {
            String executeSql = getSql(targetObject);
            System.out.println("执行sql信息为 ： " + executeSql);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }

        Object call;
        try {
            call = superCall.call();
        } catch (Exception e) {
            e.printStackTrace();
            throw new RuntimeException(e);
        } finally {
            Long end = System.currentTimeMillis();
            System.out.println(targetMethod.getName() + "  耗时：" + (end - start) + "ms");
        }
        return call;
    }

    /**
     * 获取sql语句
     * @param preparedStatement
     * @return
     * @throws Exception
     */
    private static String getSql(Object preparedStatement) throws Exception {
        Field sqlField = findField(preparedStatement.getClass(), "originalSql");
        if (sqlField == null) {
            throw new NoSuchFieldException("originalSql");
        }
        sqlField.setAccessible(true);
        return (String) sqlField.get(preparedStatement);
    }


    /**
     * 获取字段
     * @param clazz
     * @param fieldName
     * @return
     */
    private static Field findField(Class<?> clazz, String fieldName) {
        while (clazz != null) {
            try {
                System.out.println("子类没有对应字段，获取父类信息" + clazz.getName());
                return clazz.getDeclaredField(fieldName);
            } catch (NoSuchFieldException e) {
                clazz = clazz.getSuperclass();
            }
        }
        return null;
    }

}
